package com.easylinkin.linkappapi.asset.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.asset.entity.AdeviceVo;
import com.easylinkin.linkappapi.asset.entity.Asset;
import com.easylinkin.linkappapi.asset.entity.UserVo;
import com.easylinkin.linkappapi.asset.mapper.AssetMapper;
import com.easylinkin.linkappapi.asset.service.AssetRefDeviceService;
import com.easylinkin.linkappapi.asset.service.AssetRefManagerService;
import com.easylinkin.linkappapi.asset.service.AssetService;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.device.entity.Device;
import com.easylinkin.linkappapi.operatelog.constant.LogConstant.LogModule;
import com.easylinkin.linkappapi.operatelog.constant.LogConstant.LogOperateType;
import com.easylinkin.linkappapi.operatelog.entity.ObjectOperateLog;
import com.easylinkin.linkappapi.operatelog.service.ObjectOperateLogService;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import com.easylinkin.linkappapi.security.entity.LinkappUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 设备资产表，关联两张表 关联1  资产表-资产设备表 关联2  资产表-资产用户表 服务实现类
 * </p>
 *
 * @author XuGuoQing
 * @since 2020-04-15
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class AssetServiceImpl extends ServiceImpl<AssetMapper, Asset> implements AssetService {

    private static final int NO_DELETE = 1;

    @Resource
    private CommonService commonService;
    @Resource
    private AssetRefManagerService assetRefManagerService;
    @Resource
    private AssetRefDeviceService assetRefDeviceService;

    @Resource
    LinkappUserContextProducer linkappUserContextProducer;

    @Resource
    ObjectOperateLogService objectOperateLogService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateLinkappAsset(Asset asset) {
        Assert.notNull(asset, "参数不能为空");
        Asset assetExist = getExistAsset(asset.getId());
        Assert.notNull(assetExist, "资产不存在");
        if (asset.getAssetNo() != null) {
            Assert.isTrue(asset.getAssetNo().equals(assetExist.getAssetNo()), "资产编号不允许修改");
        }
        if (asset.getAssetAreaId()!= null) {
            Assert.isTrue(asset.getAssetAreaId().equals(assetExist.getAssetAreaId()), "资产空间不允许修改");
        }
        boolean iseAssetNameNotRepeat = ifAssetNameNotExist(asset.getAssetName()) || asset.getAssetName().equals(assetExist.getAssetName());
        Assert.isTrue(iseAssetNameNotRepeat, "资产名不能重复");
        validParamFormat(asset);
        commonService.setModifyInfo(asset);
        //先检查管理人员和设备是否发生变化，没有变化不做变更
        //先检查管理人员需不需要修改
        String assetId = asset.getId();
        List<String> managerIdList = asset.getManagerIdList();
        //添加的设备列表
        List<String> addDeviceIdList = getDeviceIdsFromDevices(asset.getAddDeviceList());

        //删除的设备列表
        List<String> deleteDeviceIdList = getDeviceIdsFromDevices(asset.getDeleteDeviceList());

        List<String> assetIdList = new ArrayList<>();
        assetIdList.add(assetId);
        //管理人列表是否发生变化,变化则更新
        boolean isAssetRefManagers = assetRefManagerService.isAssetRefManagers(assetId, managerIdList);
        if (!isAssetRefManagers) {
            assetRefManagerService.batchDelete(assetIdList);
            assetRefManagerService.batchAdd(assetId, managerIdList);
        }
        // 添加
        if (!ObjectUtils.isEmpty(addDeviceIdList)) {
            assetRefDeviceService.batchAdd(assetId, addDeviceIdList);
            ObjectOperateLog objectOperateLog = new ObjectOperateLog(LogModule.ASSET.getName(), LogOperateType.ASSET_BINDING_DEVICE);
            objectOperateLog.setContent(LogOperateType.ASSET_BINDING_DEVICE + ",设备编号:" + getDeviceCodesFromDevices(asset.getAddDeviceList()));
            addLog(asset, objectOperateLog);
        }
        // 删除
        if (!ObjectUtils.isEmpty(asset.getDeleteDeviceList())) {
            assetRefDeviceService.deleteByDeviceIds(assetId, deleteDeviceIdList);
            ObjectOperateLog objectOperateLog = new ObjectOperateLog(LogModule.ASSET.getName(), LogOperateType.ASSET_UNBIND_DEVICE);
            objectOperateLog.setContent(LogOperateType.ASSET_UNBIND_DEVICE + ",设备编号:" + getDeviceCodesFromDevices(asset.getDeleteDeviceList()));
            addLog(asset, objectOperateLog);
        }
        return this.updateById(asset);
    }

    private List<String> getDeviceIdsFromDevices(List<Device> devices){
        if(CollectionUtils.isEmpty(devices)){
            return null;
        }
        return devices.stream().map(Device::getId).collect(Collectors.toList());
    }

    private List<String> getDeviceCodesFromDevices(List<Device> devices){
        if(CollectionUtils.isEmpty(devices)){
            return null;
        }
        return devices.stream().map(Device::getCode).collect(Collectors.toList());
    }

    @Override
    public boolean addLinkappAsset(Asset asset) {
        //这里需要事物的控制，暂时先不做
        Assert.notNull(asset, "参数不能为空");
        Assert.notNull(asset.getAssetAreaId(), "资产位置不能为空");
        Assert.notNull(asset.getManagerIdList(), "管理人员不能为空");
        Assert.isTrue(ifAssetNameNotExist(asset.getAssetName()), "资产名不能重复");
        commonService.setCreateAndModifyInfo(asset);
        LinkappUser user = linkappUserContextProducer.getCurrent();
        asset.setTenantId(user.getTenantId());
        this.save(asset);
        assetRefManagerService.batchAdd(asset.getId(), asset.getManagerIdList());
        assetRefDeviceService.batchAdd(asset.getId(), getDeviceIdsFromDevices(asset.getAddDeviceList()));
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteLinkappAsset(List<Asset> assetList) {
        Assert.notEmpty(assetList, "删除的次产列表不能为空");
        //这里同样需要事物的控制
        List<String> assetIdList = assetList.stream().map(Asset::getId).collect(Collectors.toList());
        for (Asset asset : assetList) {
            if (removeById(asset.getId())) {
                ObjectOperateLog objectOperateLog = new ObjectOperateLog(LogModule.ASSET.getName(), LogOperateType.ASSET_DELETE);
                objectOperateLog.setContent(LogOperateType.ASSET_DELETE + ",资产名称为：" + asset.getAssetName());
                addLog(asset, objectOperateLog);
            }
        }
        assetRefManagerService.batchDelete(assetIdList);
        assetRefDeviceService.batchDelete(assetIdList);

        return true;
    }

    public void addLog(Asset asset, ObjectOperateLog objectOperateLog) {
        objectOperateLog.setObjectId(asset.getId());
        objectOperateLog.setObjectKey(asset.getAssetName());
        commonService.setLogUserInfo(objectOperateLog);
        objectOperateLogService.addLog(objectOperateLog);
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public IPage<Asset> getPage(IPage page, Asset asset) {
        IPage<Asset> list = baseMapper.getAsset(page, asset);
        if (list.getRecords() != null) {
            list.getRecords().forEach(item -> {
                setManagerIdAndName(item);
            });
        }
        return list;
    }

    private void setManagerIdAndName(Asset item) {
        List<UserVo> manages = baseMapper.getManagersByAssertId(item.getId());
        List<String> manageNames = new ArrayList<>();
        List<String> manageIds = new ArrayList<>();
        if (StringUtils.equals(item.getSpaceId(), item.getAssetAreaId())) {
            item.setAreaPath(null);
        }
        if (null != manages) {
            manages.forEach(m -> {
                manageNames.add(m.getUserName());
                manageIds.add(m.getUserId());
            });
        }
        item.setManagerIdList(manageIds);
        item.setManagerNameList(manageNames);
    }


    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public IPage<Device> getDvicePageByAssetId(IPage page, AdeviceVo adeviceVo) {
        IPage<Device> p = baseMapper.getDvicePageByAssetId(page, adeviceVo);
        if (null != p && p.getRecords() != null) {
            setDeviceAreaName(p.getRecords());
        }
        return p;
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public IPage<Device> getUnCoonectDvicePageByAssetId(IPage page, AdeviceVo adeviceVo) {
        IPage<Device> p = baseMapper.getUnCoonectDviceByAreaId(page, adeviceVo);
        if (null != p && p.getRecords() != null) {
            setDeviceAreaName(p.getRecords());
        }
        return p;
    }

    void setDeviceAreaName(List<Device> list) {
        if (null != list) {
            list.forEach(d -> {
                if (StringUtils.equals(d.getSpaceId(), d.getAreaId())) {
                    d.setAreaPath(null);
                }
            });
        }
    }


    @Override
    public List<Device> getDviceByAssetId(AdeviceVo adeviceVo) {
        List<Device> p = baseMapper.getDvicePageByAssetId(adeviceVo);
        if (null != p) {
            setDeviceAreaName(p);
        }
        return p;
    }

    @Override
    public List<UserVo> queryManager() {
        //查询当前租户下所有的manager
        LinkappUser user = linkappUserContextProducer.getCurrent();
        return baseMapper.getAllManagers(user.getTenantId());
    }


    @Override
    public Map<String, Integer> queryDayAndMonthCreates() {
        return baseMapper.queryDayAndMonthCreates();
    }

    @Override
    public Asset queryLinkappAssetById(Asset asset) {
        Asset a = baseMapper.getAsset(asset);
        Assert.notNull(a, "资产不存在");
        setManagerIdAndName(a);
        return a;
    }

    public Asset getExistAsset(String assetId) {
        QueryWrapper<Asset> wrapper = new QueryWrapper<>();
        wrapper.eq("id", assetId).eq("delete_state", NO_DELETE);
        return baseMapper.selectOne(wrapper);
    }

    /**
     * 校验参数格式
     */
    private void validParamFormat(Asset asset) {
        Assert.isTrue(asset.getAssetNo() == null || asset.getAssetNo().length() <= 32, "code超长");
        Assert.isTrue(asset.getAssetName() == null || asset.getAssetName().length() <= 32, "名称超长");
        Assert.isTrue(asset.getAssetDesc() == null || asset.getAssetDesc().length() <= 255, "备注超长");
    }

    boolean ifAssetNameNotExist(String assetName) {
        QueryWrapper<Asset> wrapper = new QueryWrapper<>();
        wrapper.eq("asset_name", assetName).eq("delete_state", NO_DELETE);
        List<Asset> assetExist = this.list(wrapper);
        return assetExist.size() == 0;
    }


}
